package me.stone.stanimeclient.core.ui.item

import android.content.Context
import android.os.Build
import android.text.Spannable
import android.text.SpannableString
import androidx.annotation.RequiresApi
import androidx.appcompat.content.res.AppCompatResources
import androidx.databinding.BindingAdapter
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import me.stone.stanimeclient.core.common.di.ApplicationScope
import me.stone.stanimeclient.core.common.extensions.sp
import me.stone.stanimeclient.core.common.utils.WhileViewSubscribed
import me.stone.stanimeclient.core.model.FanEpisodeData
import me.stone.stanimeclient.core.model.FanEpisodeItem
import me.stone.stanimeclient.core.ui.R
import me.stone.stanimeclient.core.ui.adapters.FanEpisodeAdapter
import me.stone.stanimeclient.core.ui.adapters.listener.OnItemClickListener
import me.stone.stanimeclient.core.ui.adapters.listener.OnItemSelectListener
import javax.inject.Inject
import kotlin.math.roundToInt


@Suppress("UNUSED")
object EpisodeBindingAdapters {

    @JvmStatic
    @BindingAdapter("episodeAdapter")
    fun bindEpisodeItemAdapter(
        recyclerView: RecyclerView,
        adapter: FanEpisodeAdapter
    ) {
        recyclerView.adapter = adapter
    }

}

class EpisodeBindingHelper @Inject constructor(
    val adapter: FanEpisodeAdapter,
    @ApplicationContext private val context: Context,
    @ApplicationScope private val coroutineScope: CoroutineScope
) : OnTabSelectedListener {

    private val _selectedEpisodeItem = MutableStateFlow<FanEpisodeItem?>(null)

    val selectedEpisodeItemFlow: StateFlow<FanEpisodeItem?> = _selectedEpisodeItem

    var selectedEpisodeItem: FanEpisodeItem? = null
        private set

    val sortToggleLabel: IToggleText = SortToggleLabel(context, coroutineScope)

    private fun collectToggleState() = coroutineScope.launch {
        sortToggleLabel.state
            .distinctUntilChangedBy { it }
            .onEach { if (it) adapter.toSortASC() else adapter.toSortDESC() }
            .collect()
    }

    init {
        adapter.enableDefaultSelected = false
        adapter.itemSelectListener = OnItemSelectListener {
            selectedEpisodeItem = it
            coroutineScope.launch { _selectedEpisodeItem.emit(it) }
        }
        collectToggleState()
    }

    private val _resources = MutableStateFlow<List<FanEpisodeData>>(emptyList())

    private val _currResource = MutableStateFlow(-1)

    @RequiresApi(Build.VERSION_CODES.M)
    val resourceTabs: StateFlow<List<CharSequence>> = _resources
        .map { dataList ->
            dataList.map { data ->
                context.buildTabString(data.playerName, data.playerIsVip)
            }
        }
        .stateIn(coroutineScope, WhileViewSubscribed, emptyList())

    @RequiresApi(Build.VERSION_CODES.M)
    val singleResource: StateFlow<CharSequence?> = _resources
        .map { dataList ->
            dataList.firstOrNull()?.let {
                context.buildTabString(it.playerName, it.playerIsVip)
            }
        }
        .stateIn(coroutineScope, WhileViewSubscribed, null)

    @Suppress("UNUSED")
    val currEpisodeList: StateFlow<List<FanEpisodeItem>> = _currResource
        .combine(_resources) { curr, resources ->
            if (curr >= 0 && curr < resources.size) {
                resources[curr].episodeList
            } else {
                emptyList()
            }
        }
        .onEach { adapter.submitList(it) }
        .stateIn(coroutineScope, SharingStarted.Eagerly, emptyList())

    val hasEpisodeData: StateFlow<Boolean> = _resources
        .map { it.isNotEmpty() }
        .stateIn(coroutineScope, SharingStarted.Eagerly, false)

    fun update(resources: List<FanEpisodeData>) {
        coroutineScope.launch { _resources.emit(resources) }
        coroutineScope.launch { _currResource.emit(0) }
    }

    override fun onTabSelected(tab: TabLayout.Tab) {
        coroutineScope.launch { _currResource.emit(tab.position) }
    }

    override fun onTabUnselected(tab: TabLayout.Tab?) { }

    override fun onTabReselected(tab: TabLayout.Tab?) { }

    @RequiresApi(Build.VERSION_CODES.M)
    private fun Context.buildTabString(name: String, isVip: Boolean): CharSequence {
        if (!isVip) return SpannableString(name)
        val iconSize = 16f.sp.roundToInt()
        val drawable = AppCompatResources
            .getDrawable(this, R.drawable.ic_common_vip)?.apply {
                setBounds(0, 0, iconSize, iconSize)
                setTint(getColor(R.color.md_theme_primary))
            } ?: return SpannableString(name)
        return SpannableString("${name}V").apply {
            setSpan(
                CenteredImageSpan(drawable),
                name.length, name.length + 1,
                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
            )
        }
    }

    private class SortToggleLabel(
        context: Context,
        private val coroutineScope: CoroutineScope
    ) : IToggleText {

        private val asc = context.buildToggleText(
            R.string.sort_down, R.drawable.ic_common_sort_down
        )

        private val desc = context.buildToggleText(
            R.string.sort_up, R.drawable.ic_common_sort_up
        )

        private val _state = MutableStateFlow(true)

        override val label: StateFlow<CharSequence>
            get() = _state
                .map { if (it) asc else desc }
                .stateIn(coroutineScope, SharingStarted.Eagerly, asc)

        override val state: StateFlow<Boolean>
            get() = _state
                .stateIn(coroutineScope, SharingStarted.Eagerly, true)

        override fun toggle() {
            val newValue = !_state.value
            coroutineScope.launch {
                _state.emit(newValue)
            }
        }

    }

}